import logging
from random import randint

from memoization import cached

from lakesuperior.api import resource as rsrc_api
from lakesuperior.api import query as qry_api
from lakesuperior.dictionaries.namespaces import ns_collection as nsc
from rdflib import URIRef, Literal

from grayspread import lsenv


logger = logging.getLogger(__name__)

txn_ctx = lsenv.app_globals.rdf_store.txn_ctx

highlight_types = (
        'Action', 'Agent', 'Artifact', 'Document', 'Idea', 'Material', 'Place')


def get_resource(uid, inbound=True):
    """ Get an individual resource. """
    return rsrc_api.get(uid, repr_options={'incl_inbound': inbound})

def get_legacy_uid(uid):
    """
    Get a resource UID by its legacy UID.
    """
    uids = qry_api.triple_match(
            p=nsc['lii'].legacyUid, o=Literal(uid, datatype=nsc['xsd'].integer))
    logger.info(f'Legacy UID resource(s) found: {uids}')

    return uids.pop().replace(nsc['fcres'], '')


def get_rdf_types(rsrc):
    """ Get all RDF types of a resource. """
    with txn_ctx():
        return rsrc.types


def get_lii_types(rsrc):
    """ Get grayspread types of a resource. """
    with txn_ctx():
        return {t for t in rsrc.user_types if nsc['lii'] in t}


@cached(ttl=60)
def get_all_uids(type_):
    """
    Get all resource UIDs by RDF type.

    This is used to randomize results. Since it is a very expensive operation,
    it is cached in memory and the random pick function is applied
    separately.

    Arguments:
        type_ (rdflib.term.URIRef): RDF type to look for.

    Return:
        tuple: UID strings.
    """
    urns = qry_api.triple_match(p=nsc['rdf'].type, o=type_)

    return tuple(urn.replace(nsc['fcres'], '') for urn in urns)


def random_highlight_types(ct):
    """
    Get a given number of random highlight categories.

    This function ensures that all three categories are different.
    """
    types = list(highlight_types)

    # If ct is greater than the list size, add a duplicate to it until it
    # reaches or exceeds ct.
    while ct > len(types):
        types += highlight_types

    return {types.pop(randint(0, len(types) - 1)) for _ in range(ct)}


def random_uids(ct):
    """
    Get random UIDs from a given number of random highlight categories.

    Arguments:
        ct(int): Number of categories to get.

    Return:
        dict: dictionary of category names as keys, and UIDs as values.
    """
    ret = {}
    for type_ in random_highlight_types(ct):
        uids = get_all_uids(nsc['lii'][type_])
        ret[type_] = uids[randint(0, len(uids) - 1)]

    return ret

